/**

	Bitfield.c
	==========
	
	Little endian dynamic bitfield
	
**/


/**

	Includes
	========
	
	- stdlib.h	: malloc, free
	- stdint.h	: uint8_t
	- string.h	: memset
	- bitfield.h	: self header
	
**/

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "bitfield.h"



/**

   Function: void bf_bit_set(uint8_t* byte, uint8_t n)
   ---------------------------------------------------
   
   Set bit `n` in little endian `byte`.

**/

static void bf_bit_set(uint8_t* byte, uint8_t n)
{
  if (n < 8)
    {
      *byte |= (uint8_t)(1<<(7-n));
    }
  return;
}



/**

   Function: void bf_bit_unset(uint8_t* byte, uint8_t n)
   -----------------------------------------------------
   
   Unset bit `n` in little endian `byte`.

**/

static void bf_bit_unset(uint8_t* byte, uint8_t n)
{
  if (n < 8)
    {
      *byte &= (uint8_t)(~(1<<(7-n)));
    }
  return;
}


/**
   
   Function: uint8_t bf_bit_isset(uint8_t* byte, uint8_t n)
   --------------------------------------------------------
   
   Tell if bit `n` is set  in little endian `byte`.

**/

static uint8_t bf_bit_isset(uint8_t* byte, uint8_t n)
{
  if (n < 8)
    {
      return ( (*byte) & (uint8_t)((1<<(7-n))) );
    }
  return 0;
}



/**

   Function: int bf_set(struct bitfield* bf, uint16_t n)
   -----------------------------------------------------
   
   Set bit `n` in bitfield `bf`.
   
**/

int bf_set(struct bitfield* bf, uint16_t n)
{
  if ( (n >= bf->n) && ((bf->n-1)/8 != n/8)  )
    {
      uint8_t* bits;
      uint16_t i;
		
      /* Allocate needed bytes */
      bits = (uint8_t*)malloc(sizeof(uint8_t)*((n/8)+1));
      if ( bits == NULL)
	{
	  return EXIT_FAILURE;
	}
		
      /* Nullify */
      memset(bits,0,sizeof(uint8_t)*((n/8)+1));
		
      /* Copy bits */
      for(i=0;i<bf->n;i++)
	{
	  if ( bf_isset(bf,i) )
	    {
	      bf_bit_set(&bits[i/8],i%8);
	    }
	}
		
      /* Swap */
      free(bf->bits);
      bf->bits = bits;
    }
	
  /* Update count */
  if (n >= bf->n)
    {
      bf->n = n+1;
    }
	
  /* Set bit */
  bf_bit_set(&(bf->bits[n/8]),n%8);
	
  return EXIT_SUCCESS;
}



/**
   
   Function: int bf_unset(struct bitfield* bf, uint16_t n)
   -------------------------------------------------------
   
   Unset bit `n` in bitfield `bf`.

**/

int bf_unset(struct bitfield* bf, uint16_t n)
{
  if ( (n >= bf->n) && ((bf->n-1)/8 != n/8) )
    {
      uint8_t* bits;
      uint16_t i;

      /* Allocate needed bytes */
      bits = (uint8_t*)malloc(sizeof(uint8_t)*((n/8)+1));
      if ( bits == NULL)
	{
	  return EXIT_FAILURE;
	}
		
      /* Nullify */
      memset(bits,0,sizeof(uint8_t)*((n/8)+1));
		
      /* Copy bits */
      for(i=0;i<bf->n;i++)
	{
	  if (bf_isset(bf,i))
	    {
	      bf_bit_set(&bits[i/8],i%8);
	    }
	}
		
      /* Swap */
      free(bf->bits);
      bf->bits = bits;
    }
	
  /* Update count */
  if (n >= bf->n)
    {
      bf->n = n+1;
    }
	
  /* Set bit */
  bf_bit_unset(&(bf->bits[n/8]),n%8);
	
  return EXIT_SUCCESS;
}



/**

   Function: uint8_t bf_isset(struct bitfield* bf, uint16_t n)
   ----------------------------------------------------------
   
   Tell if bit `n` is set in bitfield `bf`.

**/

uint8_t bf_isset(struct bitfield* bf, uint16_t n)
{
  if ( (n < bf->n) )
    {
      return bf_bit_isset(&(bf->bits[n/8]),n%8);
    }
  return 0;
}




/**

   Function: struct bitfield* bf_create(struct bitfield* clone)
   ------------------------------------------------------------
   
   Create a new bitfield. If `clone` is null, an empty bitfield is returned,
   otherwise a clone is returned.
   
**/

struct bitfield* bf_create(struct bitfield* clone)
{
  struct bitfield* bf;
  uint8_t* bits;
	
  if (clone == NULL)
    {
      /* Allocate a minimal bits array */
      bits = (uint8_t*)malloc(sizeof(uint8_t));
      if ( bits == NULL )
	{
	  return NULL;
	}
		
      /* Nullify */
      memset(bits,0,sizeof(uint8_t));
		
      /* Allocate bitfield */
      bf = (struct bitfield*)malloc(sizeof(struct bitfield));
      if (bf == NULL)
	{
	  free(bits);
	  return NULL;
	}
		
      /* Fill fields */
      bf->bits = bits;
      bf->n = 0;
    }
  else
    {
      uint16_t i;
		
      /* Allocate a bits array  */
      bits = (uint8_t*)malloc(sizeof(uint8_t)*((clone->n/8)+1));
      if ( bits == NULL )
	{
	  return NULL;
	}
		
      /* Nullify */
      memset(bits,0,sizeof(uint8_t)*((clone->n/8)+1));
		
      /* Allocate bitfield */
      bf = (struct bitfield*)malloc(sizeof(struct bitfield));
      if (bf == NULL)
	{
	  free(bits);
	  return NULL;
	}
		
      /* Fill fields */
      bf->bits = bits;
      bf->n = clone->n;		
		
      /* Clone */
      for(i=0;i<clone->n;i++)
	{
	  if (bf_isset(clone,i))
	    {
	      bf_set(bf,i);
	    }
	}

    }
	
  return bf;
	
}


/**

   Function: void bf_delete(struct bitfield* bf)
   ---------------------------------------------
   
   Delete a bitfield
	
**/

void bf_delete(struct bitfield* bf)
{
  if (bf != NULL)
    {
      /* Free pointers */
      if (bf->bits != NULL)
	{
	  free(bf->bits);
	}
      free(bf);
    }
  
  return;
}


/**

   Function: int bs_compare(struct bitfield* bf1,struct bitfield* bf2)
   -------------------------------------------------------------------

   Compare `bf1` and `bf2`. Return positive integer if `bf1` > `bf2`,
   negative integer if `bf1` < `bf2` and 0 otherwise.

**/

int bf_compare(struct bitfield* bf1,struct bitfield* bf2)
{
  uint16_t i,n;
  
  n = bf1->n > bf2->n ? bf1->n : bf2->n ;
  i = 0;

  while( bf_isset(bf1,i) == bf_isset(bf2,i) )
    {
      i++;
      if (i == n)
	{
	  break;
	}
    }

    if (i == n)
      {
	/* Equality */
	return 0;
      }
    else
      {
	if (bf_isset(bf1,i))
	  {
	    /* `bf1` greater */
	    return 1;
	  }
	else
	  {
	    /* `bf2` greater */
	    return -1;
	  }
      }
}
